home *** CD-ROM | disk | FTP | other *** search
/ Programming a Multiplayer FPS in DirectX / Programming a Multiplayer FPS in DirectX (Companion CD).iso / DirectX / dxsdk_oct2004.exe / dxsdk.exe / Samples / C++ / Direct3D / StateManager / EffectStateManager.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2004-09-27  |  17.0 KB  |  442 lines

  1. //--------------------------------------------------------------------------------------
  2. // File: EffectStateManager.h
  3. //
  4. // Implementation of a custom ID3DXEffectStateManager interface.
  5. //
  6. // Copyright (c) Microsoft Corporation. All rights reserved.
  7. //--------------------------------------------------------------------------------------
  8. #include "dxstdafx.h"
  9. #include "EffectStateManager.h"
  10.  
  11.  
  12. //--------------------------------------------------------------------------------------
  13. // STL dependancies
  14. //--------------------------------------------------------------------------------------
  15. #pragma warning ( push )
  16. #pragma warning ( disable : 4512 ) // 'class' : assignment operator could not be generated
  17. #pragma warning ( disable : 4702 ) // unreachable code
  18. #include <map>
  19. #include <vector>
  20. #pragma warning ( pop )
  21. using std::map;
  22. using std::vector;
  23.  
  24.  
  25. //--------------------------------------------------------------------------------------
  26. // Base implementation of a custom ID3DXEffectStateManager interface
  27. // This implementation does nothing more than forward all state change commands to the
  28. // appropriate D3D handler.
  29. // An interface that implements custom state change handling may be derived from this
  30. // (such as statistical collection, or filtering of redundant state change commands for
  31. // a subset of states)
  32. //--------------------------------------------------------------------------------------
  33. class CBaseStateManager : public CStateManagerInterface
  34. {
  35. protected:
  36.     LPDIRECT3DDEVICE9 m_pDevice;
  37.     LONG              m_lRef;
  38.     UINT              m_nTotalStateChanges;
  39.     UINT              m_nTotalStateChangesPerFrame;
  40.     WCHAR             m_wszFrameStats[256];
  41. public:
  42.     CBaseStateManager( LPDIRECT3DDEVICE9 pDevice )
  43.         : m_lRef( 1UL ),
  44.           m_pDevice( pDevice ),
  45.           m_nTotalStateChanges( 0 ),
  46.           m_nTotalStateChangesPerFrame( 0 )
  47.     {
  48.         // Increment the reference count on the device, because a pointer to it has
  49.         // been copied for later use
  50.         m_pDevice->AddRef();
  51.         m_wszFrameStats[0] = 0;
  52.     }
  53.     
  54.     virtual ~CBaseStateManager()
  55.     {
  56.         // Release the reference count held from the constructor
  57.         m_pDevice->Release();
  58.     }
  59.  
  60.     // Must be invoked by the application anytime it allows state to be
  61.     // changed outside of the D3DX Effect system.
  62.     // An entry-point for this should be provided if implementing custom filtering of redundant
  63.     // state changes.
  64.     virtual void DirtyCachedValues()
  65.     {
  66.     }
  67.  
  68.     virtual LPCWSTR EndFrameStats()
  69.     {
  70.         if( m_nTotalStateChangesPerFrame != m_nTotalStateChanges )
  71.         {
  72.             _snwprintf( m_wszFrameStats, 
  73.                         256,
  74.                         L"Frame Stats:\nTotal State Changes (Per Frame): %d",
  75.                         m_nTotalStateChanges );
  76.  
  77.             m_wszFrameStats[255] = 0;
  78.             m_nTotalStateChangesPerFrame = m_nTotalStateChanges;
  79.         }
  80.  
  81.         m_nTotalStateChanges = 0;
  82.  
  83.         return m_wszFrameStats;
  84.     }
  85.  
  86.     // methods inherited from ID3DXEffectStateManager
  87.     STDMETHOD(QueryInterface)(THIS_ REFIID iid, LPVOID *ppv)
  88.     {
  89.         if (iid == IID_IUnknown || iid == IID_ID3DXEffectStateManager)
  90.         {
  91.             *ppv = static_cast<ID3DXEffectStateManager*>(this);
  92.         } 
  93.         else
  94.         {
  95.             *ppv = NULL;
  96.             return E_NOINTERFACE;
  97.         }
  98.         
  99.         reinterpret_cast<IUnknown*>(this)->AddRef();
  100.         return S_OK;
  101.     }
  102.     STDMETHOD_(ULONG, AddRef)(THIS)
  103.     {
  104.         return (ULONG)InterlockedIncrement( &m_lRef );
  105.     }
  106.     STDMETHOD_(ULONG, Release)(THIS)
  107.     {
  108.         if( 0L == InterlockedDecrement( &m_lRef ) )
  109.         {
  110.             delete this;
  111.             return 0L;
  112.         }
  113.  
  114.         return m_lRef;
  115.     }
  116.     STDMETHOD(SetRenderState)(THIS_ D3DRENDERSTATETYPE d3dRenderState, DWORD dwValue )
  117.     {
  118.         m_nTotalStateChanges++;
  119.         return m_pDevice->SetRenderState( d3dRenderState, dwValue );
  120.     }
  121.     STDMETHOD(SetSamplerState)(THIS_ DWORD dwStage, D3DSAMPLERSTATETYPE d3dSamplerState, DWORD dwValue )
  122.     {
  123.         m_nTotalStateChanges++;
  124.         return m_pDevice->SetSamplerState( dwStage, d3dSamplerState, dwValue );
  125.     }
  126.     STDMETHOD(SetTextureStageState)(THIS_ DWORD dwStage, D3DTEXTURESTAGESTATETYPE d3dTextureStageState, DWORD dwValue )
  127.     {
  128.         m_nTotalStateChanges++;
  129.         return m_pDevice->SetTextureStageState( dwStage, d3dTextureStageState, dwValue );
  130.     }
  131.     STDMETHOD(SetTexture)(THIS_ DWORD dwStage, LPDIRECT3DBASETEXTURE9 pTexture )
  132.     {
  133.         m_nTotalStateChanges++;
  134.         return m_pDevice->SetTexture( dwStage, pTexture );
  135.     }
  136.     STDMETHOD(SetVertexShader)(THIS_ LPDIRECT3DVERTEXSHADER9 pShader )
  137.     {
  138.         m_nTotalStateChanges++;
  139.         return m_pDevice->SetVertexShader( pShader );
  140.     }
  141.     STDMETHOD(SetPixelShader)(THIS_ LPDIRECT3DPIXELSHADER9 pShader )
  142.     {
  143.         m_nTotalStateChanges++;
  144.         return m_pDevice->SetPixelShader( pShader );
  145.     }
  146.     STDMETHOD(SetFVF)(THIS_ DWORD dwFVF )
  147.     {
  148.         m_nTotalStateChanges++;
  149.         return m_pDevice->SetFVF( dwFVF );
  150.     }
  151.     STDMETHOD(SetTransform)(THIS_ D3DTRANSFORMSTATETYPE State, CONST D3DMATRIX *pMatrix )
  152.     {
  153.         m_nTotalStateChanges++;
  154.         return m_pDevice->SetTransform( State, pMatrix );
  155.     }
  156.     STDMETHOD(SetMaterial)(THIS_ CONST D3DMATERIAL9 *pMaterial )
  157.     {
  158.         m_nTotalStateChanges++;
  159.         return m_pDevice->SetMaterial( pMaterial );
  160.     }
  161.     STDMETHOD(SetLight)(THIS_ DWORD Index, CONST D3DLIGHT9 *pLight )
  162.     {
  163.         m_nTotalStateChanges++;
  164.         return m_pDevice->SetLight( Index, pLight );
  165.     }
  166.     STDMETHOD(LightEnable)(THIS_ DWORD Index, BOOL Enable )
  167.     {
  168.         m_nTotalStateChanges++;
  169.         return m_pDevice->LightEnable( Index, Enable );
  170.     }
  171.     STDMETHOD(SetNPatchMode)(THIS_ FLOAT NumSegments )
  172.     {
  173.         m_nTotalStateChanges++;
  174.         return m_pDevice->SetNPatchMode( NumSegments );
  175.     }
  176.     STDMETHOD(SetVertexShaderConstantF)(THIS_ UINT RegisterIndex,
  177.                                         CONST FLOAT *pConstantData,
  178.                                         UINT RegisterCount )
  179.     {
  180.         m_nTotalStateChanges++;
  181.         return m_pDevice->SetVertexShaderConstantF( RegisterIndex,
  182.                                                     pConstantData,
  183.                                                     RegisterCount );
  184.     }
  185.     STDMETHOD(SetVertexShaderConstantI)(THIS_ UINT RegisterIndex,
  186.                                         CONST INT *pConstantData,
  187.                                         UINT RegisterCount )
  188.     {
  189.         m_nTotalStateChanges++;
  190.         return m_pDevice->SetVertexShaderConstantI( RegisterIndex,
  191.                                                     pConstantData,
  192.                                                     RegisterCount );
  193.     }
  194.     STDMETHOD(SetVertexShaderConstantB)(THIS_ UINT RegisterIndex,
  195.                                         CONST BOOL *pConstantData,
  196.                                         UINT RegisterCount )
  197.     {
  198.         m_nTotalStateChanges++;
  199.         return m_pDevice->SetVertexShaderConstantB( RegisterIndex,
  200.                                                     pConstantData,
  201.                                                     RegisterCount );
  202.     }
  203.     STDMETHOD(SetPixelShaderConstantF)(THIS_ UINT RegisterIndex,
  204.                                        CONST FLOAT *pConstantData,
  205.                                        UINT RegisterCount )
  206.     {
  207.         m_nTotalStateChanges++;
  208.         return m_pDevice->SetPixelShaderConstantF( RegisterIndex,
  209.                                                    pConstantData,
  210.                                                    RegisterCount );
  211.     }
  212.     STDMETHOD(SetPixelShaderConstantI)(THIS_ UINT RegisterIndex,
  213.                                         CONST INT *pConstantData,
  214.                                         UINT RegisterCount )
  215.     {
  216.         m_nTotalStateChanges++;
  217.         return m_pDevice->SetPixelShaderConstantI( RegisterIndex,
  218.                                                    pConstantData,
  219.                                                    RegisterCount );
  220.     }
  221.     STDMETHOD(SetPixelShaderConstantB)(THIS_ UINT RegisterIndex,
  222.                                        CONST BOOL *pConstantData,
  223.                                        UINT RegisterCount )
  224.     {
  225.         m_nTotalStateChanges++;
  226.         return m_pDevice->SetPixelShaderConstantB( RegisterIndex,
  227.                                                    pConstantData,
  228.                                                    RegisterCount );
  229.     }
  230. };
  231.  
  232.  
  233. //--------------------------------------------------------------------------------------
  234. // Templated class for caching and duplicate state change filtering of paired types
  235. // (such as D3DRENDERSTATETYPE/DWORD value types)
  236. //--------------------------------------------------------------------------------------
  237. template < typename _Kty, typename _Ty >
  238. class multicache
  239. {
  240. protected:
  241.     map< _Kty, _Ty > cache;         // A map provides a fast look-up of contained states
  242.                                     // and furthermore ensures that duplicate key values
  243.                                     // are not present.
  244.                                     // Additionally, dirtying the cache can be done by
  245.                                     // clear()ing the container.
  246. public:
  247.     // Command to dirty all cached values
  248.     inline void dirtyall( )
  249.     {
  250.         cache.clear();
  251.     }
  252.  
  253.     // Command to dirty one key value
  254.     inline void dirty( _Kty key )
  255.     {
  256.         map< _Kty, _Ty >::iterator it = cache.find( key );
  257.         if( cache.end() != it )
  258.             cache.erase( it );
  259.     }
  260.  
  261.     // Called to update the cache
  262.     // The return value indicates whether or not the update was a redundant change.
  263.     // A value of 'true' indicates the new state was unique, and must be submitted
  264.     // to the D3D Runtime.
  265.     inline bool set_val( _Kty key, _Ty value )
  266.     {
  267.         map< _Kty, _Ty >::iterator it = cache.find( key );
  268.         if( cache.end() == it )
  269.         {
  270.             cache.insert( map< _Kty, _Ty >::value_type(key, value) );
  271.             return true;
  272.         }
  273.         if( it->second == value )
  274.             return false;
  275.         it->second = value;
  276.         return true;
  277.     }
  278. };
  279.  
  280.  
  281. //--------------------------------------------------------------------------------------
  282. // Implementation of a state manager that filters redundant state change commands.
  283. // This implementation is useful on PURE devices.
  284. // PURE HWVP devices do not implement redundant state change filtering.
  285. // States that may be useful to filter on PURE device are:
  286. //      Render States
  287. //      Texture Stage States
  288. //      Sampler States
  289. // See the Direct3D SDK Documentation for further details on pure device state change
  290. // behavior.
  291. //--------------------------------------------------------------------------------------
  292. #define CACHED_STAGES 2        // The number of stages to cache
  293.                                // Remaining stages are simply passed through with no
  294.                                // redundancy filtering.
  295.                                // For this sample, the first two stages are cached, while
  296.                                // the remainder are passed through
  297.  
  298. class CPureDeviceStateManager : public CBaseStateManager
  299. {
  300. protected:
  301.     typedef multicache<D3DSAMPLERSTATETYPE, DWORD> samplerStageCache;
  302.     typedef multicache<D3DTEXTURESTAGESTATETYPE, DWORD> textureStateStageCache;
  303. protected:
  304.     multicache<D3DRENDERSTATETYPE, DWORD> cacheRenderStates;    // cached Render-States
  305.     vector<samplerStageCache>      vecCacheSamplerStates;       // cached Sampler States
  306.     vector<textureStateStageCache> vecCacheTextureStates;       // cached Texture Stage States
  307.  
  308.     UINT    m_nFilteredStateChanges;                            // Statistics -- # of redundant
  309.                                                                 // states actually filtered
  310.     UINT    m_nFilteredStateChangesPerFrame;
  311.  
  312. public:
  313.     CPureDeviceStateManager( LPDIRECT3DDEVICE9 pDevice )
  314.         : CBaseStateManager( pDevice ),
  315.           cacheRenderStates(), 
  316.           vecCacheSamplerStates( CACHED_STAGES ),
  317.           vecCacheTextureStates( CACHED_STAGES ),
  318.           m_nFilteredStateChanges( 0 ),
  319.           m_nFilteredStateChangesPerFrame( 0 )
  320.     {
  321.     }
  322.     virtual LPCWSTR EndFrameStats()
  323.     {
  324.         // If either the 'total' state changes or the 'filtered' state changes
  325.         // has changed, re-compute the frame statistics string
  326.         if( 0 != ( (m_nTotalStateChangesPerFrame  - m_nTotalStateChanges)
  327.             | (m_nFilteredStateChangesPerFrame - m_nFilteredStateChanges) ) )
  328.         {
  329.             _snwprintf( m_wszFrameStats, 
  330.                         256,
  331.                         L"Frame Stats:\nTotal State Changes (Per Frame): %d\nRedundants Filtered (Per Frame): %d",
  332.                         m_nTotalStateChanges, m_nFilteredStateChanges );
  333.  
  334.             m_wszFrameStats[255] = 0;
  335.  
  336.             m_nTotalStateChangesPerFrame = m_nTotalStateChanges;
  337.             m_nFilteredStateChangesPerFrame = m_nFilteredStateChanges;
  338.         }
  339.  
  340.         m_nTotalStateChanges = 0;
  341.         m_nFilteredStateChanges = 0;
  342.  
  343.         return m_wszFrameStats;
  344.     }
  345.     // More targeted 'Dirty' commands may be useful.
  346.     void DirtyCachedValues()
  347.     {
  348.         cacheRenderStates.dirtyall();
  349.  
  350.         vector<samplerStageCache>::iterator it_samplerStages;
  351.         for( it_samplerStages =  vecCacheSamplerStates.begin();
  352.              it_samplerStages != vecCacheSamplerStates.end();
  353.              it_samplerStages++ )
  354.             (*it_samplerStages).dirtyall();
  355.  
  356.         vector<textureStateStageCache>::iterator it_textureStages;
  357.         for( it_textureStages =  vecCacheTextureStates.begin();
  358.              it_textureStages != vecCacheTextureStates.end();
  359.              it_textureStages++ )
  360.             (*it_textureStages).dirtyall();
  361.     }
  362.  
  363.     // methods inherited from ID3DXEffectStateManager
  364.     STDMETHOD(SetRenderState)(THIS_ D3DRENDERSTATETYPE d3dRenderState, DWORD dwValue )
  365.     {
  366.         m_nTotalStateChanges++;
  367.  
  368.         // Update the render state cache
  369.         // If the return value is 'true', the command must be forwarded to
  370.         // the D3D Runtime.
  371.         if( cacheRenderStates.set_val( d3dRenderState, dwValue ) )
  372.             return m_pDevice->SetRenderState( d3dRenderState, dwValue );
  373.  
  374.         m_nFilteredStateChanges++;
  375.  
  376.         return S_OK;
  377.     }
  378.  
  379.     STDMETHOD(SetSamplerState)(THIS_ DWORD dwStage, D3DSAMPLERSTATETYPE d3dSamplerState, DWORD dwValue )
  380.     {
  381.         m_nTotalStateChanges++;
  382.  
  383.         // If this dwStage is not cached, pass the value through and exit.
  384.         // Otherwise, update the sampler state cache and if the return value is 'true', the 
  385.         // command must be forwarded to the D3D Runtime.
  386.         if( dwStage >= CACHED_STAGES || vecCacheSamplerStates[dwStage].set_val( d3dSamplerState, dwValue ) )
  387.             return m_pDevice->SetSamplerState( dwStage, d3dSamplerState, dwValue );
  388.  
  389.         m_nFilteredStateChanges++;
  390.  
  391.         return S_OK;
  392.     }
  393.  
  394.     STDMETHOD(SetTextureStageState)(THIS_ DWORD dwStage, D3DTEXTURESTAGESTATETYPE d3dTextureStageState, DWORD dwValue )
  395.     {
  396.         m_nTotalStateChanges++;
  397.  
  398.         // If this dwStage is not cached, pass the value through and exit.
  399.         // Otherwise, update the texture stage state cache and if the return value is 'true', the 
  400.         // command must be forwarded to the D3D Runtime.
  401.         if( dwStage >= CACHED_STAGES || vecCacheTextureStates[dwStage].set_val( d3dTextureStageState, dwValue ) )
  402.             return m_pDevice->SetTextureStageState( dwStage, d3dTextureStageState, dwValue );
  403.  
  404.         m_nFilteredStateChanges++;
  405.  
  406.         return S_OK;
  407.     }
  408. };
  409.  
  410.  
  411. //--------------------------------------------------------------------------------------
  412. // Create an extended ID3DXEffectStateManager instance
  413. //--------------------------------------------------------------------------------------
  414. CStateManagerInterface* CStateManagerInterface::Create( LPDIRECT3DDEVICE9 pDevice )
  415. {
  416.     CStateManagerInterface* pStateManager = NULL;
  417.  
  418.     D3DDEVICE_CREATION_PARAMETERS cp;
  419.     memset( &cp, 0, sizeof cp );
  420.  
  421.     if( SUCCEEDED( pDevice->GetCreationParameters( &cp ) ) )
  422.     {
  423.         // A PURE device does not attempt to filter duplicate state changes (with some
  424.         // exceptions) from the driver.  Such duplicate state changes can be expensive
  425.         // on the CPU.  To create the proper state manager, the application determines
  426.         // whether or not it is executing on a PURE device.
  427.         bool bPureDevice = (cp.BehaviorFlags & D3DCREATE_PUREDEVICE) != 0;
  428.         
  429.         if( bPureDevice)
  430.             pStateManager = new CPureDeviceStateManager( pDevice );
  431.         else
  432.             pStateManager = new CBaseStateManager( pDevice );
  433.     }
  434.  
  435.     if( NULL == pStateManager )
  436.     {
  437.         DXUT_ERR_MSGBOX( L"Failed to Create State Manager", E_OUTOFMEMORY );
  438.     }
  439.  
  440.     return pStateManager;
  441. }
  442.